#include "stdafx.h"
#include "v2bus.h"



using namespace BUS;

// ============================================================================
// global instances for BUS
// ============================================================================
MOD    BUS::__busModule;                //global instance of BUS modules
PIPE   BUS::__busPipe;                  //global instance of BUS pipe


// ============================================================================
// CLASS MOD::BUS
//  BUS modules manager, following are the main functions:
//      MOD::hook()     register a module to BUS
//      MOD::unhook()   remove a module from BUS 
//      MOD::find()     get the index of a registered module
// ============================================================================
MOD::MOD()
{
}

MOD::~MOD()
{
}

// ============================================================================
// function MOD::hook()     
//  register a module to BUS which compliant with MOD:API interface, with which
//  the BUS messages could be exchanged among modules.
// ============================================================================
int MOD::hook(char* modName, API* apiAddr)
{
    if(NULL == modName || NULL == apiAddr)
    {
        return -1;
    }

    int index = -1;

    // in case of _recycle is not empty, try to reuse the latest index 
    if(_recycle.size() > 0) 
    {
        index = _recycle.back();
        _recycle.pop_back();
        if(index >= 0 && index < (int)_apiList.size())
        {
            _apiList[index] = apiAddr;
        }
        else
        {
            index = -1;
        }
    }

    // if _recycle is empty then add a new index
    if(index < 0)
    {
        _apiList.push_back(apiAddr);
        index = _apiList.size() - 1;
    }

    // mapping modName to index
    _modIndex[modName] = index;

    return index;
}

// ============================================================================
// function MOD::unhook()     
//  register a module to BUS which compliant with MOD:API interface, with which
//  the BUS messages could be exchanged among modules.
// ============================================================================
void MOD::unhook(API* apiAddr)
{
    int index;

    // find the index of apiAddr
    for(index = 0; index < (int)_apiList.size(); ++index)
    {
        if(_apiList[index] == apiAddr) break;
    }

    if(index >= (int)_apiList.size()) return;

    // update the index mapping 
    for(map<string, int>::iterator it = _modIndex.begin(); it !=_modIndex.end(); ++it)
    {
        if(it->second == index)
        {
            _modIndex.erase(it);
        }
    }

    // put the index to the _recycle so that it could be reused
    _recycle.push_back(index);
}



// ============================================================================
// function MOD::find()     
//  get the index of a registered module by name.
// ============================================================================
int MOD::find(char* modName)
{
    map<string, int>::iterator it = _modIndex.find(modName);

    if(it == _modIndex.end())
    {
        return -1;
    }

    return it->second;
}

// ============================================================================
// CLASS MOD::PIPE
//  FIFO mesagge pipe of BUS, following are the main functions:
//      PIPE::init()    initialize the PIPE with specify size
//      PIPE::empty()   check PIPE is empty or not
//      PIPE::count()   return the message number in PIPE
//      PIPE::send()    send a message to PIPE
//      PIPE::first()   get the pointer of first message
//      PIPE::remove()  remove the first message
// ============================================================================
PIPE::PIPE()
{
    _bufferAddr = NULL;
    _bufferSize = 0; 
    _msgHead = NULL;
    _msgTail = NULL;
    _msgCount = 0;
    _msgLength = 0;
    _msgSpace = 0;
}

PIPE::~PIPE()
{
    destroy();
}


// ============================================================================
// function PIPE::init()     
//  initialize the PIPE with the specified size.
// ============================================================================
bool PIPE::init(int bufferSize)
{
    if(bufferSize < 0) return false;

    // release memory before creating a new one
    destroy();

    if(NULL == (_bufferAddr = new char[bufferSize])) return false;

    // reset attributes
    _bufferSize = bufferSize;
    _msgHead = _bufferAddr;
    _msgTail = _bufferAddr;
    _msgCount = 0;
    _msgLength = 0;
    _msgSpace = bufferSize;

    return true;
}

// ============================================================================
// function PIPE::destroy()
//  destroy the PIPE and release the memory.
// ============================================================================
void PIPE::destroy()
{
    if(_bufferAddr)
    {
        delete _bufferAddr;
    }

    _bufferAddr = NULL;
    _bufferSize = 0; 
    _msgHead = NULL;
    _msgTail = NULL;
    _msgCount = 0;
    _msgLength = 0;
    _msgSpace = 0;
}


// ============================================================================
// function PIPE::empty()
//  return true if the PIPE is empty, false when PIPE is not.
// ============================================================================
bool PIPE::empty()
{
    return _msgCount > 0;
}


// ============================================================================
// function PIPE::count()
//  return the message numbers in the queue
// ============================================================================
int PIPE::count()
{
    return _msgCount;
}


// ============================================================================
// function PIPE::send()
//  send a message to the PIPE
// ============================================================================
bool PIPE::send(BUS::MSG& msg, void* data)
{
    if(NULL == _msgHead)
    {
        return false;
    }

    // ensure msg.dataLen >= 0
    if(msg.dataLen < 0)
    {
        msg.dataLen = 0;
    }

    // if not enough space
    if(_msgSpace < (int)sizeof(msg) + msg.dataLen)
    {
        // totaly not enough memory
        if(_msgHead - _bufferAddr < (int)sizeof(msg) + msg.dataLen)
        {
            return false;
        }

        // reset the tail pointer
        _msgTail = _bufferAddr;
        _msgSpace = _msgHead - _bufferAddr;
    }

    // copy msg
    memcpy(_msgTail, &msg, sizeof(msg));
    _msgTail += sizeof(msg);
    _msgLength += sizeof(msg);
    _msgSpace -= sizeof(msg);

    // copy data
    if(msg.dataLen > 0)
    {
        if(data)
        {
            memcpy((void*)_msgTail, data, msg.dataLen);
        }
        _msgTail += msg.dataLen;
        _msgLength += msg.dataLen;
        _msgSpace -= msg.dataLen;
    }

    return true;
}


// ============================================================================
// function PIPE::first()
//  return the first message in PIPE
// ============================================================================
BUS::MSG* PIPE::first()
{
    return (BUS::MSG*)_msgHead;
}


// ============================================================================
// function PIPE::remove()
//  remove the first message in PIPE
// ============================================================================
bool PIPE::remove(BUS::MSG* msg)
{
    if((char*)msg != _msgHead || NULL == msg)
    {
        return false;
    }

    _msgHead += sizeof(msg) + msg->dataLen;
    _msgLength -= sizeof(msg) + msg->dataLen;
    
    // in case of tail pointer has been reset
    if(_msgTail < _msgHead)
    {
        _msgSpace += sizeof(msg) + msg->dataLen;
        if(_msgTail -_bufferAddr == _msgLength)
        {
            _msgHead = _bufferAddr;
            _msgSpace = _bufferSize - _msgLength;
        }
    }

    return true;
}


// ============================================================================
// function BUS::init()
//  remove the first message in PIPE
// ============================================================================
bool init()
{
    __busPipe.init(DEFAULT_BUFFER_SZIE * 1024);
    return true;
}



// ============================================================================
// function BUS::send() sendf()
//  //send a message to PIPE
// ============================================================================
bool send(BUS::MSG& msg, void* data)
{
    return __busPipe.send(msg, data); 
}

bool sendf(BUS::MSG& msg, void* data, ...)
{
	va_list argp;
	va_start(argp, pzlog);
    vsnprintf_s(*text, text.size(), _TRUNCATE, pzlog, argp);
    va_end(argp);

    res &= debug_file.write(*text);
    res &= debug_file.write("\n");
    return __busPipe.send(msg, data); 
}
